package com.benyi.byiee.service;
 

import java.util.Date;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.benyi.byiee.constants.EmailType;
import com.benyi.byiee.constants.UserType;
import com.benyi.byiee.constants.YesNo;
import com.benyi.byiee.dao.mappers.UserAccountMapper;
import com.benyi.byiee.dao.mappers.VerifyEmailMapper;
import com.benyi.byiee.model.api.User;
import com.benyi.byiee.model.db.UserAccount;
import com.benyi.byiee.model.db.VerifyEmail;
import com.benyi.byiee.util.OnlineUserList;
import com.benyi.byiee.util.RequestContext;
import com.benyi.util.Config;
import com.benyi.util.FileTool;
import com.benyi.util.JsonTool;
import com.benyi.util.Mail;
import com.benyi.util.Tools;
import com.benyi.util.bean.ServiceException;

import jakarta.annotation.Resource;

@Service
public class AccountService { 
	
	private static Logger log = LoggerFactory.getLogger(AccountService.class);
	
	@Resource(name="config")
	private Config config;
	
	
	@Autowired
	private UserAccountMapper userMapper;
	
	@Autowired
	private VerifyEmailMapper mailMapper;
	
	
	public UserAccount updateBase(User user ,  UserAccount ua) {
		UserAccount account = user.getAccount();
		if(ua.getIcon()!=null) {
			account.setIcon(ua.getIcon());
		}
		if(ua.getLang() != null ) {
			account.setLang(ua.getLang());
		}
		if(ua.getVname() != null) {
			account.setVname(ua.getVname());
		}			
		if(ua.getUtype() != null) {
			account.setUtype(ua.getUtype());
		} 
		int rows = userMapper.updateBaseInfo(account); 
		log.debug("update base user info,rows={}", rows);
		if(rows>0) {
			return account;
		}
		return null;
	}
	
	public UserAccount login(String email,String passwd) throws ServiceException {
		log.info("requestId:{},start login,email:{},passwd:{}",RequestContext.getRequestId(), email,passwd);
		UserAccount ua = userMapper.selectByEmail(email);
		if(ua==null) {
			log.debug("login,no email:{}",email);
			throw new ServiceException("none_account","账户或密码错误");
		}
		
		if(ua.getVerifyStatus() != YesNo.YES) {
			log.debug("login,not verified email:{}",email);
			throw new ServiceException("not_active_account","账户未激活");
		}
		
		String pwd = ua.getPasswd();
		if(pwd.length() == 32) { //MD5
			passwd = Tools.md5(passwd);
		}
		if(passwd.equalsIgnoreCase(pwd)==false) {
			log.debug("requestId:{},login,password not correct",RequestContext.getRequestId());
			throw new ServiceException("wrong_passwd","秘密错误");
		}
		
		log.debug("login , User:"+JsonTool.toString(ua));
		
		User user = new User();
		user.setEmail(ua.getEmail()); 
		user.setLastTime(System.currentTimeMillis());
		user.setToken(OnlineUserList.createToken());
		user.setFromIp(RequestContext.getRequestIp()); 
		
		user.setAccount(ua);
		
		OnlineUserList.putUser(user.getToken(), user);
		
		log.info("requeestId:{},login sucess,user:{}",RequestContext.getRequestId(),JsonTool.toString(user));
		
		ua.setPasswd(null);
		ua.setLastTm(null);
		ua.setRegTm(null);
		
		ua.setToken(user.getToken());
		
		return ua;
	} 
	
	public UserAccount logout(String token) {
		log.info("requestId:{},login out ,token:{}",RequestContext.getRequestId(),token);
		User user = OnlineUserList.getUser(token); 
		if(user == null ) {
			return null;
		}
		String ip = RequestContext.getRequestIp();
		if(ip!=null && ip.equalsIgnoreCase(user.getFromIp())) {
			OnlineUserList.removeUser(token);  
			log.info("requestId:{},login out sucess,user:{}",RequestContext.getRequestId(),JsonTool.toString(user));
		}else {
			log.info("requestId:{},login out fail,token:{}",RequestContext.getRequestId(),token);
		}
		return user.getAccount();  
	} 
	
	public UserAccount heartBeat(String token) {
		log.info("requestId:{},heart beat ,token:{}",RequestContext.getRequestId(),token);
		User user = OnlineUserList.getUser(token); 
		if(user != null) {
			user.fresh();
		} 
		return user.getAccount();  
	}
	
	public UserAccount register(String email,String passwd,String lang) throws ServiceException {
		log.info("requestId:{},start regist,email:{},passwd:{}",RequestContext.getRequestId(), email,passwd);
		UserAccount u = userMapper.selectByEmail(email);
		if(u != null) {
			log.debug("email:{} is used",email);
			throw new ServiceException("exist_account","账户已经存在");
		} 
		if(passwd == null || passwd.length()==0) {
			passwd = String.valueOf(System.currentTimeMillis() %100000);
		}
		String pwd = Tools.md5(passwd);  
		UserAccount user = new UserAccount();
		user.setEmail(email);
		user.setPasswd(pwd);
		user.setVerifyStatus(YesNo.NO);
		user.setUtype(UserType.REGISTER_USER);
		user.setRegTm(new Date()); 
		
		int rows = userMapper.insert(user); 
		log.info("requeestId:{},regist sucess,user:{},rows:{}",
				RequestContext.getRequestId(),JsonTool.toString(user),rows);
		if(rows != 1) {
			throw new ServiceException("create_account_fail","创建账户失败");
		}
		//给用户发激活码
		sendActiveMail(email,lang);
		return user;
	}
	
	public UserAccount resetPassword(String email,String passwd,String code) throws ServiceException {
		log.info("requestId:{},start regist,email:{},passwd:{},code:{}",
				RequestContext.getRequestId(), email,passwd,code);
		UserAccount u = userMapper.selectByEmail(email);
		if(u == null) {
			log.debug("user not find,email:{}",email);
			throw new ServiceException("none_account","账户不存在");
		} 
		VerifyEmail m = mailMapper.selectByEmail(email,EmailType.VERIFY);
		if(m==null || m.getStatus() != YesNo.NO) {
			throw new ServiceException("none_verify","验证邮件未发送");
		}
		if(m.getVcode().equals(code)==false) {
			log.debug("active code is not equals , email:{}",email);
			throw new ServiceException("wrong_code","验证码错误");
		}
		m.setStatus(YesNo.YES);
		m.setReadTm(new Date());
		mailMapper.updateStatus(m);
		
		String pwd = Tools.md5(passwd);  
		UserAccount user = new UserAccount();
		user.setRid(u.getRid());
		user.setPasswd(pwd);
		user.setVerifyStatus(YesNo.YES); 
		
		int rows = userMapper.updatePassword(user); 
		log.info("requeestId:{},regist sucess,user:{},rows:{}",
				RequestContext.getRequestId(),JsonTool.toString(user),rows);
		if(rows != 1) {
			throw new ServiceException("fail_update","修改密码失败");
		} 
		return user;
	}
	
	public UserAccount active(String email,String code,String passwd) throws ServiceException {
		log.info("requestId:{},start regist,email:{},code:{},passwd:{}",
				RequestContext.getRequestId(), email,code,passwd);
		UserAccount u = userMapper.selectByEmail(email);
		if(u == null) {
			log.debug("user not find,email:{}",email);
			throw new ServiceException("none_account","账户不存在");
		} 
		VerifyEmail m = mailMapper.selectByEmail(email,EmailType.ACTIVE);
		if(m==null || m.getStatus() != YesNo.NO) {
			throw new ServiceException("none_verify","验证邮件未发送");
		}
		if(m.getVcode().equals(code)==false) {
			log.debug("active code is not equals , email:{},vcode:{},inpu:{}",email,m.getVcode(),code);
			throw new ServiceException("wrong_verify","激活码错误");
		}
		m.setStatus(YesNo.YES);
		m.setReadTm(new Date());
		mailMapper.updateStatus(m);
		
		UserAccount user = new UserAccount();
		user.setRid(u.getRid());
		if(passwd!=null && passwd.length()>0) {
			user.setPasswd(Tools.md5(passwd)); //提供了密码，就要设置密码
		}else {
			user.setPasswd(u.getPasswd());
		} 
		user.setVerifyStatus(YesNo.YES); 
		
		int rows = userMapper.updatePassword(user); 
		log.info("requeestId:{},regist sucess,user:{},rows:{}",
				RequestContext.getRequestId(),JsonTool.toString(user),rows);
		if(rows != 1) {
			throw new ServiceException("fail_update","修改密码失败");
		} 
		return user;
	}
	
	public int sendActiveMail(String email,String lang) {
		log.debug("send active email, email:{},lang:{}",email,lang);
		UserAccount u = userMapper.selectByEmail(email);
		if(u==null) {
			log.debug("send active email,no account:{}",email);
			return -1;
		}
		 
		String code = String.valueOf(System.currentTimeMillis()%100000);
		long r = (long)(System.currentTimeMillis()*Math.random());
		
		while(code.length() < CODE_LENGTH ) {
			code = String.valueOf(r%10) + code;
			r = r/10;
		}
		
		MailThread thread = new MailThread(lang,email,code,EmailType.ACTIVE);
		thread.start(); 
		
		return 0;
	}
	
	private int insertActiveCode(String email,String code) {
		VerifyEmail v = new VerifyEmail();
		v.setEmail(email);
		v.setEtype(EmailType.ACTIVE);
		v.setVcode(code);
		v.setSendTm(new Date());
		v.setStatus(YesNo.NO); 
		int rows = mailMapper.insert(v); 
		log.info("send active code to mail:{},code:{},result:{}",email,code,rows);
		return rows;
	}
	
	public int sendVerifyCode(String email,String lang) {
		log.debug("send verify email, email:{},lang:{}",email,lang);
		UserAccount u = userMapper.selectByEmail(email);
		if(u==null) {
			log.debug("send active email,no email:{}",email);
			return -1;
		}
		
		String code = String.valueOf(System.currentTimeMillis()%100000);
		long r = (long)(System.currentTimeMillis()*Math.random());
		
		while(code.length() < CODE_LENGTH ) {
			code = String.valueOf(r%10) + code;
			r = r/10;
		}
		 
		MailThread thread = new MailThread(lang,email,code,EmailType.VERIFY);
		thread.start();
		return 0;
	}
	
	private int insertVerifyTask(String email,String code) {
		VerifyEmail v = new VerifyEmail();
		v.setEmail(email);
		v.setEtype(EmailType.VERIFY);
		v.setVcode(code);
		v.setSendTm(new Date());
		v.setStatus(YesNo.NO); 
		int rows = mailMapper.insert(v);
		log.info("send verify code to mail:{},code:{},result:{}",email,code,rows);
		return rows;
	}
	
	class MailThread extends Thread{
		String lang;
		String toMail;
		String vCode; 
		short type;
		
		public MailThread(String lang, String toMail, String vCode,short type) {
			this.lang = lang;
			this.toMail = toMail; 
			this.vCode = vCode;
			this.type = type;
		}
		
		public void run() { 
			
			log.debug("send email,type:{},email:{},code:{},lang:{}",type,toMail,vCode,lang);
			
			String title ;
			String model ;
			
			if(type == EmailType.VERIFY) {
				title="email_verify_title_"+lang;
				model="email_verify_file_"+lang;
			}else {
				title="email_active_title_"+lang;
				model="email_active_file_"+lang;
			} 
			
			String smtp = config.get("smtp_name");
			String port = config.get("smtp_port");
			String fromMaill = config.get("smtp_mail");
			String passwd = config.get("smtp_passwd");
			
			String subject = config.get(title);
			String content = null;
			try {
				content = FileTool.readTextFile(config.get(model));
			}catch(Exception e) {
				log.error("read email model file exception , file:{}",e , model);
			}  
			if(content==null) {
				return ;
			}
			content = Tools.replace(content, "{email}", toMail);
			content = Tools.replace(content, "{vcode}", vCode);  
			
			try {
				Mail.sendMail(smtp, port, fromMaill, passwd, toMail, subject, content); 
				log.info("send email finished,toMail:{}",toMail);
				if(type == EmailType.VERIFY) {
					insertVerifyTask(toMail,vCode);
				}else {
					if(type == EmailType.ACTIVE) {
						insertActiveCode(toMail,vCode);
					}
				}
			}catch(Exception e) {
				log.error("send email exception,toMail:{},\r\nsubject:{},\r\ncontent:{}", 
						e,toMail,subject, content); 
				return;
			}  
		}
	}
	
	private static final int CODE_LENGTH = 6;
}
